﻿
namespace System.Linq.Functional
{
    public static class CurryExtensions
    {
        #region Func
        // F# - Currying
        public static Func<TArg, Func<TResult>> Curry<TArg, TResult>(this Func<TArg, TResult> func)
        {
            return arg => () => func(arg);
        }

        // F# - Currying
        public static Func<TArg1, Func<TArg2, TResult>> Curry<TArg1, TArg2, TResult>(this Func<TArg1, TArg2, TResult> func)
        {
            return a1 => a2 => func(a1, a2);
        }

        // F# - Currying
        public static Func<TArg1, Func<TArg2, TArg3, TResult>> Curry<TArg1, TArg2, TArg3, TResult>(this Func<TArg1, TArg2, TArg3, TResult> func)
        {
            return a1 => (a2, a3) => func(a1, a2, a3);
        }

        // F# - Currying
        public static Func<TArg1, Func<TArg2, TArg3, TArg4, TResult>> Curry<TArg1, TArg2, TArg3, TArg4, TResult>(this Func<TArg1, TArg2, TArg3, TArg4, TResult> func)
        {
            return a1 => (a2, a3, a4) => func(a1, a2, a3, a4);
        }
        #endregion

        #region Func All
        // F# - Currying
        public static Func<TArg, Func<TResult>> CurryAll<TArg, TResult>(this Func<TArg, TResult> func)
        {
            return arg => () => func(arg);
        }

        // F# - Currying
        public static Func<TArg1, TArg2, Func<TResult>> CurryAll<TArg1, TArg2, TResult>(this Func<TArg1, TArg2, TResult> func)
        {
            return (a1, a2) => () => func(a1, a2);
        }

        // F# - Currying
        public static Func<TArg1, TArg2, TArg3, Func<TResult>> CurryAll<TArg1, TArg2, TArg3, TResult>(this Func<TArg1, TArg2, TArg3, TResult> func)
        {
            return (a1, a2, a3) => () => func(a1, a2, a3);
        }

        // F# - Currying
        public static Func<TArg1, TArg2, TArg3, TArg4, Func<TResult>> CurryAll<TArg1, TArg2, TArg3, TArg4, TResult>(this Func<TArg1, TArg2, TArg3, TArg4, TResult> func)
        {
            return (a1, a2, a3, a4) => () => func(a1, a2, a3, a4);
        }
        #endregion

        #region Action
        // F# - Currying
        public static Func<TArg1, Action<TArg2>> Curry<TArg1, TArg2>(this Action<TArg1, TArg2> action)
        {
            return a1 => a2 => action(a1, a2);
        }

        // F# - Currying
        public static Func<TArg1, Action<TArg2, TArg3>> Curry<TArg1, TArg2, TArg3>(this Action<TArg1, TArg2, TArg3> action)
        {
            return a1 => (a2, a3) => action(a1, a2, a3);
        }

        // F# - Currying
        public static Func<TArg1, Action<TArg2, TArg3, TArg4>> Curry<TArg1, TArg2, TArg3, TArg4>(this Action<TArg1, TArg2, TArg3, TArg4> action)
        {
            return a1 => (a2, a3, a4) => action(a1, a2, a3, a4);
        }
        #endregion

        #region Action All
        // F# - Currying
        public static Func<TArg, Action> CurryAll<TArg>(this Action<TArg> action)
        {
            return arg => () => action(arg);
        }

        // F# - Currying
        public static Func<TArg1, TArg2, Action> CurryAll<TArg1, TArg2>(this Action<TArg1, TArg2> action)
        {
            return (a1, a2) => () => action(a1, a2);
        }

        // F# - Currying
        public static Func<TArg1, TArg2, TArg3, Action> CurryAll<TArg1, TArg2, TArg3>(this Action<TArg1, TArg2, TArg3> action)
        {
            return (a1, a2, a3) => () => action(a1, a2, a3);
        }

        // F# - Currying
        public static Func<TArg1, TArg2, TArg3, TArg4, Action> CurryAll<TArg1, TArg2, TArg3, TArg4>(this Action<TArg1, TArg2, TArg3, TArg4> action)
        {
            return (a1, a2, a3, a4) => () => action(a1, a2, a3, a4);
        }
        #endregion
    }
}
